//
// Created by ly-zhouxyi on 2024/3/5.
//

#include "AudioDecoder.h"

AudioDecoder::AudioDecoder(FFmpegCallJava *callJava, PlayStatus *playStatus, int sampleRate)
        : callJava(callJava), playStatus(playStatus), sample_rate(sampleRate) {
    audioQueue = new DataQueue(playStatus);
    newSampleBuffer = static_cast<soundtouch::SAMPLETYPE *>(malloc(sample_rate * 2 * 2));
    soundTouch = new soundtouch::SoundTouch;
    soundTouch->setSampleRate(sampleRate);
    soundTouch->setChannels(2);
    soundTouch->setTempo(speed);
    soundTouch->setPitch(pitch);
}

AudioDecoder::~AudioDecoder() {

}

void *audioPlay(void *data) {
    AudioDecoder *audioDecoder = (AudioDecoder *) data;
    audioDecoder->initOpenSLES();
    pthread_exit(&audioDecoder->thread_audio_play);
}

void AudioDecoder::play() {
    // 创建播放线程
    pthread_create(&thread_audio_play, NULL, audioPlay, this);
}

/**
 * 播放   喇叭需要来主动取出数据
 * @param bufferQueue
 * @param context
 */
void pcmBufferCallBack(SLAndroidSimpleBufferQueueItf bufferQueue, void *context) {
    AudioDecoder *mAudioDecoder = (AudioDecoder *) context;
    if (mAudioDecoder != NULL) {
        int size = mAudioDecoder->getSoundTouchData();
  //      LOGE("pcmBufferCallBack  %d ", size);
        if (size > 0) {
            mAudioDecoder->clock += size / ((double) (mAudioDecoder->sample_rate * 2 * 2));
            // 100*1000字节
            if (mAudioDecoder->clock - mAudioDecoder->last_time >= 0.1) {
                mAudioDecoder->last_time = mAudioDecoder->clock;
                // pcmBufferCallBack 回调次数比较频繁    回调java
                mAudioDecoder->callJava->onTimeInfo(mAudioDecoder->clock, mAudioDecoder->duration);

                //（44100 * 2 * 2 表示：44100是频率HZ，2是立体声双通道，2是采用的16位采样即2个字节，所以总的字节数就是：44100 * 2 * 2）
            }
            (*mAudioDecoder->pcmBufferQueue)->Enqueue(mAudioDecoder->pcmBufferQueue,
                                                      (char *) mAudioDecoder->newSampleBuffer,
                                                      size * 2 * 2);
        }
    }
}

/**
 * 初始化 OpenSlEs
 */
void AudioDecoder::initOpenSLES() {
    // 1.创建引擎接口
    SLresult result;
    // 创建引擎
    result = slCreateEngine(&engineObject, 0, 0, 0, 0, 0);
    // 实现（Realize）engineObject接口对象
    result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
    // 通过engineObject的GetInterface方法初始化engineEngine
    result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);


    //2，创建混音器
    const SLInterfaceID mids[1] = {SL_IID_ENVIRONMENTALREVERB};
    const SLboolean mreq[1] = {SL_BOOLEAN_FALSE};
    // 利用引擎接口对象创建混音器接口对象
    result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, mids, mreq);


    (void) result;
    result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);

    // 利用混音器接口对象初始化具体混音器实例
    (void) result;
    result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB,
                                              &outputMixEnvironmentalReverb);

    if (SL_RESULT_SUCCESS == result) {
        result = (*outputMixEnvironmentalReverb)->SetEnvironmentalReverbProperties(
                outputMixEnvironmentalReverb, &reverbSettings);
        LOGE("SetEnvironmentalReverbProperties result %d", result);
        (void) result;
    }
    //3. 适配播放器
    // 配置 audio sink
    SLDataLocator_OutputMix outputMix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
    SLDataSink audioSnk = {&outputMix, 0};

    // 3 配置 audio source
    SLDataLocator_AndroidSimpleBufferQueue android_queue = {
            SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
            2};

    SLDataFormat_PCM pcm = {
            SL_DATAFORMAT_PCM,//播放pcm格式的数据
            2,//2个声道（立体声）
            static_cast<SLuint32>(getCurrentSampleRateForOpenSlEs(sample_rate)),//44100hz的频率
            SL_PCMSAMPLEFORMAT_FIXED_16,//位数 16位
            SL_PCMSAMPLEFORMAT_FIXED_16,//和位数一致就行
            SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,//立体声（前左前右）
            SL_BYTEORDER_LITTLEENDIAN//结束标志
    };
    SLDataSource slDataSource = {&android_queue, &pcm};

    // 创建播放器
    const SLInterfaceID ids[3] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME, SL_IID_MUTESOLO};
    const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};

    (*engineEngine)->CreateAudioPlayer(engineEngine, &pcmPlayerObject, &slDataSource, &audioSnk,
                                       3,
                                       ids, req);
    // 初始化播放器
    (*pcmPlayerObject)->Realize(pcmPlayerObject, SL_BOOLEAN_FALSE);
    // 得到接口后调用  获取Player接口
    (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_PLAY, &pcmPlayerPlay);
    // 获取声道操作接口
    (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_MUTESOLO, &pcmMutePlay);
    // 播放暂停恢复的接口
    (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_VOLUME, &pcmVolumePlay);
    // 注册回调缓冲区 获取缓冲队列接口
    (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_BUFFERQUEUE, &pcmBufferQueue);
    //注册缓冲接口回调
    (*pcmBufferQueue)->RegisterCallback(pcmBufferQueue, pcmBufferCallBack, this);
    // 设置播放状态
    (*pcmPlayerPlay)->SetPlayState(pcmPlayerPlay, SL_PLAYSTATE_PLAYING);
    callJava->onPlaying(true);
    pcmBufferCallBack(pcmBufferQueue, this);
}

int AudioDecoder::getCurrentSampleRateForOpenSlEs(int sample_rate) {
    int rate = 0;
    switch (sample_rate) {
        case 8000:
            rate = SL_SAMPLINGRATE_8;
            break;
        case 11025:
            rate = SL_SAMPLINGRATE_11_025;
            break;
        case 12000:
            rate = SL_SAMPLINGRATE_12;
            break;
        case 16000:
            rate = SL_SAMPLINGRATE_16;
            break;
        case 22050:
            rate = SL_SAMPLINGRATE_22_05;
            break;
        case 24000:
            rate = SL_SAMPLINGRATE_24;
            break;
        case 32000:
            rate = SL_SAMPLINGRATE_32;
            break;
        case 44100:
            rate = SL_SAMPLINGRATE_44_1;
            break;
        case 48000:
            rate = SL_SAMPLINGRATE_48;
            break;
        case 64000:
            rate = SL_SAMPLINGRATE_64;
            break;
        case 88200:
            rate = SL_SAMPLINGRATE_88_2;
            break;
        case 96000:
            rate = SL_SAMPLINGRATE_96;
            break;
        case 192000:
            rate = SL_SAMPLINGRATE_192;
            break;
        default:
            rate = SL_SAMPLINGRATE_44_1;
    }
    return rate;
}

int AudioDecoder::getAudioBuffer(void **pcmBuffer) {
    while (playStatus != NULL && !playStatus->exit) {
        // 初始化
        avPacket = av_packet_alloc();
        // 读取队列中的avPacket
        if (audioQueue->getAvPacket(avPacket) != 0) {
            av_packet_free(&avPacket);
            av_free(avPacket);
            avPacket = NULL;
            continue;
        }
        // 送人数据解码
        if (avcodec_send_packet(avCodecContext, avPacket) != 0) {
            av_packet_free(&avPacket);
            av_free(avPacket);
            avPacket = NULL;
            continue;
        }
        // 初始化数据接受
        avFrame = av_frame_alloc();
        if (avcodec_receive_frame(avCodecContext, avFrame) == 0) {
            // 获取通道
            if (avFrame->channels && avFrame->channel_layout == 0) {
                avFrame->channel_layout = av_get_default_channel_layout(avFrame->channels);
            } else if (avFrame->channels == 0 && avFrame->channel_layout > 0) {
                avFrame->channels = av_get_channel_layout_nb_channels(avFrame->channel_layout);
            }

            // 设置转换器参数
            SwrContext *swr_ctx = swr_alloc_set_opts(
                    NULL,
                    AV_CH_LAYOUT_STEREO,
                    AV_SAMPLE_FMT_S16,
                    avFrame->sample_rate,
                    avFrame->channel_layout,
                    (AVSampleFormat) avFrame->format,
                    avFrame->sample_rate,
                    NULL, NULL
            );
            // 初始化转换器
            if (!swr_ctx || swr_init(swr_ctx) < 0) {
                av_packet_free(&avPacket);
                av_free(avPacket);
                avPacket = NULL;
                av_frame_free(&avFrame);
                av_free(avFrame);
                avFrame = NULL;
                swr_free(&swr_ctx);
                continue;
            }

            int out_count = (int) (
                    (int64_t) avFrame->nb_samples * avFrame->sample_rate /
                    avFrame->sample_rate +
                    256);


            int out_size = av_samples_get_buffer_size(NULL, avFrame->channels, out_count,
                                                      AV_SAMPLE_FMT_S16, 0);
            if (out_size < 0) {
                LOGE("av_samples_get_buffer_size() failed\n");
                return -1;
            }
            // av_fast_malloc(&buffer, &buffer_size, out_size);
            buffer = static_cast<uint8_t *>(av_malloc(out_size));

            // 数据转换
            newSamples = swr_convert(
                    swr_ctx,
                    &buffer,
                    out_count,
                    (const uint8_t **) avFrame->data,
                    avFrame->nb_samples);


            int out_channels = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO);
            int bytes_per_sample = av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);
            data_size = newSamples * out_channels * bytes_per_sample;
            // 计算时间 pts 序号 *时间戳
            now_time = avFrame->pts * av_q2d(time_base);
            // 当前帧的时间小于当前播放时间 同步到当前播放时间
            if (now_time < clock) {
                now_time = clock;
            }
            clock = now_time;
            // 赋值
            *pcmBuffer = buffer;
            av_packet_free(&avPacket);
            av_free(avPacket);
            avPacket = NULL;
            av_frame_free(&avFrame);
            av_free(avFrame);
            avFrame = NULL;
            swr_free(&swr_ctx);
            break;
        } else {
            av_packet_free(&avPacket);
            av_free(avPacket);
            avPacket = NULL;
            av_frame_free(&avFrame);
            av_free(avFrame);
            avFrame = NULL;
            continue;
        }
    }
    return data_size;
}

void AudioDecoder::setSpeed(float speed) {
    this->speed = speed;
    if (soundTouch != NULL) {
        soundTouch->setTempo(speed);
    }
}

void AudioDecoder::setPitch(float pitch) {
    this->pitch = pitch;
    if (soundTouch != NULL) {
        soundTouch->setPitch(pitch);
    }
}

void AudioDecoder::pause() {
    playStatus->pause = true;
    if (pcmPlayerPlay != NULL) {
        (*pcmPlayerPlay)->SetPlayState(pcmPlayerPlay, SL_PLAYSTATE_PAUSED);
        callJava->onPlaying(false);
    }
}

void AudioDecoder::resume() {
    playStatus->pause = false;
    if (pcmPlayerPlay != NULL) {
        (*pcmPlayerPlay)->SetPlayState(pcmPlayerPlay, SL_PLAYSTATE_PLAYING);
        callJava->onPlaying(true);
    }
}


void AudioDecoder::setVolume(float volume) {
    // 声音0是最大声音，-5000就听不见了
    // 音量 0 是最大，负值是越来越小。
    float v = (1.0f - volume * 1.0f / 100.0f) * -5000;
    LOGE("volume %f", v);
    if (pcmVolumePlay != NULL) {
        (*pcmVolumePlay)->SetVolumeLevel(pcmVolumePlay, v);
    }
}

int AudioDecoder::getCurrentVolume() {
    SLmillibel volume = -10000;
    if (pcmVolumePlay != NULL) {
        (*pcmVolumePlay)->GetVolumeLevel(pcmVolumePlay, &volume);
        LOGE("getCurrentVolume  volume %d ",volume);
    }
    return volume;
}


void AudioDecoder::setVolumeMute(bool mute) {
    if (pcmVolumePlay != NULL) {
        (*pcmVolumePlay)->SetMute(pcmVolumePlay,mute);
    }
}

void AudioDecoder::setMute(int channel) {
    if (pcmMutePlay == NULL) {
        LOGE(" pcmMutePlay 接口未初始化 ")
        return;
    }
    switch (channel) {
        case 0:
            // 正常
            (*pcmMutePlay)->SetChannelMute(pcmMutePlay, 1, false);
            (*pcmMutePlay)->SetChannelMute(pcmMutePlay, 0, false);
            break;
        case 1:
            // right
            (*pcmMutePlay)->SetChannelMute(pcmMutePlay, 1, false);
            (*pcmMutePlay)->SetChannelMute(pcmMutePlay, 0, true);
            break;
        case 2:
            // lift
            (*pcmMutePlay)->SetChannelMute(pcmMutePlay, 1, true);
            (*pcmMutePlay)->SetChannelMute(pcmMutePlay, 0, false);
            break;
        case 3:
            // all
            (*pcmMutePlay)->SetChannelMute(pcmMutePlay, 1, true);
            (*pcmMutePlay)->SetChannelMute(pcmMutePlay, 0, true);
            break;

    }
}


/**
 * 获取处理过后的波
 * @return
 */
int AudioDecoder::getSoundTouchData() {
    while (playStatus != NULL && !playStatus->exit) {
        outBuffer = NULL;
        if (!isSync) {
            isSync = true;
            dataSize = getAudioBuffer(reinterpret_cast<void **>(&outBuffer));
            if (dataSize > 0) {
                for (int i = 0; i < data_size / 2 + 1; i++) {
                    //short  2个字节  pcm数据   ====波形
                    newSampleBuffer[i] = (outBuffer[i * 2] | ((outBuffer[i * 2 + 1]) << 8));
                }
                // soundTouch   进行波的整理  转换统一格式后的 newSamples
                soundTouch->putSamples(newSampleBuffer, newSamples);
                // 接受一个新波 newSampleBuffer
                num = soundTouch->receiveSamples(newSampleBuffer, data_size / 4);
            //    LOGE("第一个num %d ", num);
            } else {
                soundTouch->flush();
            }
        }
        if (num == 0) {
            isSync = false;
            continue;
        } else {
            if (outBuffer == NULL) {
                // 当第一次波形无法处理时 需要等到第二次接受波形
                num = soundTouch->receiveSamples(newSampleBuffer, data_size / 4);
            //    LOGE("第二个num %d ", num);
                if (num == 0) {
                    isSync = false;
                    continue;
                }
            }
            return num;
        }
    }
    return 0;
}


void AudioDecoder::release() {
    //    队列
    if (audioQueue != NULL) {
        delete (audioQueue);
        audioQueue = NULL;
    }
    if (pcmPlayerObject != NULL) {
        (*pcmPlayerObject)->Destroy(pcmPlayerObject);
        pcmPlayerObject = NULL;
        pcmPlayerPlay = NULL;
        pcmBufferQueue = NULL;
    }

    if (outputMixObject != NULL) {
        (*outputMixObject)->Destroy(outputMixObject);
        outputMixObject = NULL;
        outputMixEnvironmentalReverb = NULL;
    }

    if (engineObject != NULL) {
        (*engineObject)->Destroy(engineObject);
        engineObject = NULL;
        engineEngine = NULL;
    }

    if (buffer != NULL) {
        free(buffer);
        buffer = NULL;
    }

    if (newSampleBuffer != NULL) {
        free(newSampleBuffer);
        newSampleBuffer = NULL;
    }

    if (avCodecContext != NULL) {
        avcodec_close(avCodecContext);
        avcodec_free_context(&avCodecContext);
        avCodecContext = NULL;
    }

    if (playStatus != NULL) {
        playStatus = NULL;
    }
    if (callJava != NULL) {
        callJava = NULL;
    }
}






